package com.gitee.sop.sopauth.service;

import com.alibaba.fastjson.JSONObject;
import com.gitee.sop.message.manager.SenderManagerService;
import com.gitee.sop.message.manager.SenderManagerServiceImpl;
import com.gitee.sop.message.util.DateUtils;
import com.gitee.sop.mongodb.MongoQuery;
import com.gitee.sop.redis.service.RedisService;
import com.gitee.sop.servercommon.constant.Constants;
import com.gitee.sop.servercommon.exception.ServiceException;
import com.gitee.sop.servercommon.result.R;
import com.gitee.sop.servercommon.util.ObjectUtil;
import com.gitee.sop.servercommon.util.StringUtils;
import com.gitee.sop.sopauth.auth.FetchTokenParam;
import com.gitee.sop.sopauth.auth.impl.BaseServiceImpl;
import com.gitee.sop.sopauth.controller.param.CodeParam;
import com.gitee.sop.sopauth.entity.SenderConfig;
import com.gitee.sop.sopauth.enums.TemplateStatus;
import com.gitee.sop.sopauth.properties.SenderProperties;
import com.gitee.sop.sopauth.util.ReUtil;
import com.gitee.sop.sopauth.util.SmsCodeGenerator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * 邮箱/短信验证码获取
 *
 * @author wlx
 */
@Component
public class SendCodeHandler extends BaseServiceImpl {
    @Resource
    private SenderManagerService senderManagerService;

    @Resource
    private SenderProperties senderProperties;

    @Autowired
    private RedisService redisService;


    /**
     * 下发验证码
     *
     * @param codeParam
     * @return
     */
    public Object handleCode(CodeParam codeParam) {
        String type = codeParam.getSendType();
        String receiver = codeParam.getUsername();
        String appId = codeParam.getAppId();
        if (!ReUtil.isEmailNO(receiver) && !ReUtil.isMobileNO(receiver)) {
            throw new ServiceException("请输入正确的手机号/邮箱");
        } else {
            String limitKey = Constants.RECEIVER_LIMIT_KEY + appId + ":" + receiver;
            Integer dayLimit = redisService.getCacheObject(limitKey);
            Integer limitDay = senderProperties.getLimitDay();
            //默认没配置是不受任何限制
            if (StringUtils.isNotNull(dayLimit)
                    && StringUtils.isNotNull(limitDay)
                    && !SenderManagerServiceImpl.SenderEnum.normal.getType().equals(type)
                    && dayLimit.intValue() >= limitDay.intValue()) {
                throw new ServiceException("已超过当日发送限制，请联系系统管理员");
            } else {
                String randomCode = SmsCodeGenerator.randomCode();
                String content = "您的验证码为：" + randomCode + "（" + Constants.CAPTCHA_EXPIRATION + "分钟内有效）";
                boolean send;
                String result = null;
                if (SenderManagerServiceImpl.SenderEnum.normal.getType().equals(type)) {
                    result = "【蓝星云开放平台】" + content;
                    send = true;
                } else if (SenderManagerServiceImpl.SenderEnum.sms.getType().equals(type) || SenderManagerServiceImpl.SenderEnum.email.getType().equals(type)) {
                    //发送模板 YiMeiSmsSender RongTongDaSmsSender Email163Sender EmailQQSender
                    JSONObject jsonObject = initConfig(appId);
                    if (Objects.isNull(jsonObject)) {
                        throw new ServiceException("发送模板获取失败");
                    }
                    String senderCode = jsonObject.getString("senderCode");
                    send = senderManagerService.send(senderCode, receiver, content, type, jsonObject);
                } else {
                    throw new ServiceException("暂不支持此类型下发验证码");
                }
                if (send) {
                    if (redisService.hasKey(limitKey)) {
                        redisService.increment(limitKey, 1L);
                    } else {
                        Date curr = new Date();
                        Date dateEndTime = DateUtils.getDateEndTime(curr);
                        Long betweenMin = DateUtils.getBetweenMin(dateEndTime, curr);
                        redisService.setCacheObject(limitKey, 1, betweenMin, TimeUnit.MINUTES);
                    }
                    String verifyKey = Constants.RECEIVER_CODE_KEY + appId + ":" + receiver;
                    redisService.setCacheObject(verifyKey, randomCode, Constants.CAPTCHA_EXPIRATION, TimeUnit.MINUTES);
                    return R.ok(result);
                }
            }

        }
        throw new ServiceException("获取验证码失败");
    }

    /**
     * 校验验证码
     *
     * @param codeParam
     */
    public void validateCode(FetchTokenParam codeParam) {
        //@TODO 是否开启验证码模式，开启时校验

        String code = codeParam.getSendCode();
        String receiver = codeParam.getUsername();
        String appId = codeParam.getAppId();

        if (StringUtils.isBlank(code)) {
            throw new ServiceException("请先获取验证码");
        }

        if (StringUtils.isBlank(receiver)) {
            throw new ServiceException("接收者已失效");
        }

        if (StringUtils.isBlank(appId)) {
            throw new ServiceException("应用ID不能为空");
        }

        String verifyKey = Constants.RECEIVER_CODE_KEY + appId + ":" + receiver;
        String captcha = redisService.getCacheObject(verifyKey);
        redisService.deleteObject(verifyKey);
        if (!code.equalsIgnoreCase(captcha)) {
            throw new ServiceException("验证码错误");
        }
    }

    /**
     * 新增消息核心配置信息
     *
     * @param senderConfig
     */
    public void addMessageConfig(SenderConfig senderConfig) {
        String appId = senderConfig.getAppId();
        String type = senderConfig.getType();
        if ("auto".equals(type)) {
            //@TODO 1、自配置短信/邮箱配置信息型，配置好相关参数即可使用
            //查询数据库中指定APP应用已开启的配置信息，若有则并将其修改为禁用状态
            List<MongoQuery> mongoQueries = new ArrayList<>();
            mongoQueries.add(new MongoQuery("appId", appId));
            mongoQueries.add(new MongoQuery("status", TemplateStatus.normal.getCode()));
            JSONObject jsonObject = mongoDbUtil.queryOne(getCollectionName(), mongoQueries, JSONObject.class);
            if (Objects.nonNull(jsonObject)) {
                //已存在开启的配置信息，将其修改为禁用状态
                jsonObject.put("status", TemplateStatus.DISABLE.getCode());
                mongoDbUtil.updateOne(getCollectionName(), "_id", jsonObject.getString("_id"), jsonObject);
            }
            //整理对应模板配置参数，并生成有效的开始和结束时间，保存到数据库中
            JSONObject extData = senderConfig.getExtData();
            if (Objects.nonNull(extData)) {
                senderConfig.setStatus(TemplateStatus.normal.getCode());
                senderConfig.setStartTime(new Date());
                Date endDate = DateUtils.addDays(senderConfig.getStartTime(), 365);
                senderConfig.setEndTime(endDate);
                Map<String, Object> map = ObjectUtil.toMap(senderConfig);
                map.remove("extData");
                extData.putAll(map);
                //存入数据库
                List<JSONObject> list = new ArrayList<>();
                list.add(extData);
                mongoDbUtil.insertDocument(getCollectionName(), list);
            }
        } else if ("pay".equals(type)) {
            //@TODO 2、收费使用，支付完成后可在有效期内直接使用


        }
    }

    public JSONObject initConfig(String appId) {
        List<MongoQuery> mongoQueries = new ArrayList<>();
        mongoQueries.add(new MongoQuery("appId", appId));
        mongoQueries.add(new MongoQuery("status", TemplateStatus.normal.getCode()));
        JSONObject jsonObject = mongoDbUtil.queryOne(getCollectionName(), mongoQueries, JSONObject.class);
        if (Objects.nonNull(jsonObject)) {
            return jsonObject;
        }
        return null;
    }

    @Override
    protected String getCollectionName() {
        return "senderConfig";
    }
}